﻿using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Threading;
using System.Collections.Concurrent;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.IO;
using System.Collections;
using static System.Net.Mime.MediaTypeNames;
using JESAI.Core.Extensions;
using sysenum = System.Enum;
using Microsoft.Extensions.Logging;
using JESAI.Core.Util.Helpers;
using JESAI.Core.Serialize;

namespace JESAI.Core.Extensions
{
    /// <summary>
    /// 通用对象扩展方法
    /// </summary>
    public static class ObjectExtensions
    {

        private static readonly TimeSpan timeSpan = TimeSpan.FromHours(8);
        static ObjectExtensions()
        {
            var now = DateTime.Now;
            var utcNow = now.ToUniversalTime();
            timeSpan = now - utcNow;
        }

        #region 私有方法,使用Convert类进行转换
        private static List<TypeCode> _baseTypes = new List<TypeCode>
        {
            TypeCode.Byte,TypeCode.SByte,
            TypeCode.Int16,TypeCode.UInt16,
            TypeCode.Int32,TypeCode.UInt32,
            TypeCode.Int64,TypeCode.UInt64,
            TypeCode.Single,TypeCode.Double,TypeCode.Decimal,
            TypeCode.Char,TypeCode.Boolean,TypeCode.String,TypeCode.DateTime
        };

        private static object _baseConvert(TypeCode typeCode, object value)
        {
            switch (typeCode)
            {
                case TypeCode.Byte:
                    {
                        return Convert.ToByte(value);
                    }
                case TypeCode.SByte:
                    {
                        return Convert.ToSByte(value);
                    }
                case TypeCode.Int16:
                    {
                        return Convert.ToInt16(value);
                    }
                case TypeCode.UInt16:
                    {
                        return Convert.ToUInt16(value);
                    }
                case TypeCode.Int32:
                    {
                        return Convert.ToInt32(value);
                    }
                case TypeCode.UInt32:
                    {
                        return Convert.ToUInt32(value);
                    }
                case TypeCode.Int64:
                    {
                        return Convert.ToInt64(value);
                    }
                case TypeCode.UInt64:
                    {
                        return Convert.ToUInt64(value);
                    }
                case TypeCode.Single:
                    {
                        return Convert.ToSingle(value);
                    }
                case TypeCode.Double:
                    {
                        return Convert.ToDouble(value);
                    }
                case TypeCode.Decimal:
                    {
                        return Convert.ToDecimal(value);
                    }
                case TypeCode.Char:
                    {
                        return Convert.ToChar(value);
                    }
                case TypeCode.Boolean:
                    {
                        return Convert.ToBoolean(value);
                    }
                case TypeCode.String:
                    {
                        return Convert.ToString(value);
                    }
                case TypeCode.DateTime:
                    {
                        return Convert.ToDateTime(value);
                    }
                default:
                    {
                        return null;
                    }
            }
        }
        #endregion

        #region 通用转换方法 object.To<T>()
        /// <summary>
        /// 通用转换方法
        /// </summary>
        /// <param name="value">待转换对象</param>
        /// <param name="parameters">转换时用到的参数,目前仅用于string -> DateTime/DateTimeOffset</param>
        public static T To<T>(this object value, params object[] parameters)
        {
            if (value is T) return (T)value;
            Type type = typeof(T);
            if (value == null || value is DBNull)
            {
                //引用类型: 返回默认 即: null
                if (!type.IsValueType) return default;
                //可空类型: 返回默认 即: null
                if (type.IsNullable()) return default;
                //null => int 只能报错
                throw new Exception($"无法将 null 或 dbnull 转为为:[{type.GetClassFullName()}]类型!");
            }
            return (T)value.To(type, parameters);
            //return To(value, type, parameters).To<T>();
        }

        /// <summary>
        /// 通用转换方法
        /// </summary>
        /// <param name="value">待转换对象</param>
        /// <param name="type">目的类型</param>
        /// <param name="parameters">转换时用到的参数,目前仅用于string -> DateTime/DateTimeOffset</param>
        /// <returns></returns>
        public static object To(this object value, Type type, params object[] parameters)
        {
            //null -> 其他,DBNull -> 其他 (DataTable中使用)
            if (value == null || value is DBNull)
            {
                //引用类型: 返回默认 即: null
                if (!type.IsValueType) return null;
                //可空类型: 返回默认 即: null
                if (type.IsNullable()) return null;
                //null => int 只能报错
                throw new Exception($"无法将 null 或 dbnull 转为为:[{type.GetClassFullName()}]类型!");
            }
            //子类 -> 父类
            if (type.IsAssignableFrom(value.GetType()))
            {
                return value;
            }

            if (type.IsNullable()) type = type.GenericTypeArguments[0];

            //其他 -> string
            if (type == typeof(string))
            {
                if (value is DateTime dt)
                {
                    if (parameters.EnumerableIsNotNullOrEmpty())
                    {
                        return dt.ToString(parameters[0].ToString());
                    }
                    return dt.ToString();
                }
                if (value is DateTimeOffset offset)
                {
                    if (parameters.EnumerableIsNotNullOrEmpty())
                    {
                        return offset.ToString(parameters[0].ToString());
                    }
                    return offset.ToString();
                }
                #if NET6
                if (value is DateOnly dateOnly)
                {
                    if (parameters.IsNotNullOrEmpty())
                    {
                        return dateOnly.ToString(parameters[0].ToString());
                    }
                    return dateOnly.ToString();
                }
                if (value is TimeOnly timeOnly)
                {
                    if (parameters.IsNotNullOrEmpty())
                    {
                        return timeOnly.ToString(parameters[0].ToString());
                    }
                    return timeOnly.ToString();
                }
#endif
                if (value is Guid guid)
                {
                    if (parameters.EnumerableIsNotNullOrEmpty())
                    {
                        return guid.ToString(parameters[0].ToString());
                    }
                    return guid.ToString();
                }
                object obj = value?.ToString();
                return obj;
            }

            if (type.IsValueType)
            {
                //值类型
                #region 枚举
                if (type.IsEnum)
                {
                    //枚举转换
                    return sysenum.Parse(type, value?.ToString(), true);
                }
                #endregion
                #region 字符串转日期
                if (value is string && (type == typeof(DateTime) || type == typeof(DateTimeOffset)))
                {
                    if (type == typeof(DateTime))
                    {
                        if (parameters != null && parameters.Length > 0)
                        {
                            value = DateTime.ParseExact(value.ToString(), parameters[0].ToString(), null);
                        }
                        else
                        {
                            value = DateTime.Parse(value.ToString());
                        }
                        return value;
                    }
                    if (type == typeof(DateTimeOffset))
                    {
                        if (parameters != null && parameters.Length > 0)
                        {
                            value = DateTimeOffset.ParseExact(value.ToString(), parameters[0].ToString(), null);
                        }
                        else
                        {
                            value = DateTimeOffset.Parse(value.ToString());
                        }
                        return value;
                    }
                }
                #endregion
                #region DateOnly & TimeOnly & DateTime & DateTimeOffset & TimeSpan
                // string => DateOnly or TimeOnly
#if NET6
                if (value is string && (type == typeof(DateOnly) || type == typeof(TimeOnly)))
                {
                    if (type == typeof(DateOnly))
                    {
                        if (parameters != null && parameters.Length > 0)
                        {
                            value = DateOnly.ParseExact(value.ToString(), parameters[0].ToString(), null);
                        }
                        else
                        {
                            value = DateOnly.Parse(value.ToString());
                        }
                        return value;
                    }
                    if (type == typeof(TimeOnly))
                    {
                        if (parameters != null && parameters.Length > 0)
                        {
                            value = TimeOnly.ParseExact(value.ToString(), parameters[0].ToString(), null);
                        }
                        else
                        {
                            value = TimeOnly.Parse(value.ToString());
                        }
                        return value;
                    }
                }

                //DateTime or DateTimeOffset or TimeSpan => DateOnly or TimeOnly
                if ((value is DateTime || value is DateTimeOffset || value is TimeSpan) && (type == typeof(DateOnly) || type == typeof(TimeOnly)))
                {
                    if (type == typeof(DateOnly))
                    {
                        if (value is DateTime dt)
                        {
                            value = DateOnly.FromDateTime(dt);
                        }
                        else if (value is DateTimeOffset dto)
                        {
                            value = DateOnly.FromDateTime(dto.DateTime);
                        }
                        else if (value is TimeSpan ts)
                        {
                            throw new Exception("无法从TimeSpan转到DateOnly!");
                        }
                        return value;
                    }
                    if (type == typeof(TimeOnly))
                    {
                        if (value is DateTime dt)
                        {
                            value = TimeOnly.FromDateTime(dt);
                        }
                        else if (value is DateTimeOffset dto)
                        {
                            value = TimeOnly.FromDateTime(dto.DateTime);
                        }
                        else if (value is TimeSpan ts)
                        {
                            value = TimeOnly.FromTimeSpan(ts);
                        }
                        return value;
                    }
                }

                //DateOnly or TimeOnly => DateTime or DateTimeOffset or TimeSpan
                if ((value is DateOnly || value is TimeOnly) && (type == typeof(DateTime) || type == typeof(DateTimeOffset) || type == typeof(TimeSpan)))
                {
                    if (type == typeof(DateTime))
                    {
                        if (value is DateOnly dateOnly)
                        {
                            value = new DateTime(dateOnly.Year, dateOnly.Month, dateOnly.Day);
                        }
                        else if (value is TimeOnly timeOnly)
                        {
                            value = new DateTime(1970, 1, 1, timeOnly.Hour, timeOnly.Minute, timeOnly.Second, timeOnly.Millisecond);
                        }
                        return value;
                    }
                    if (type == typeof(DateTimeOffset))
                    {
                        if (value is DateOnly dateOnly)
                        {
                            value = new DateTimeOffset(dateOnly.Year, dateOnly.Month, dateOnly.Day, 0, 0, 0, timeSpan);
                        }
                        else if (value is TimeOnly timeOnly)
                        {
                            value = new DateTimeOffset(1970, 1, 1, timeOnly.Hour, timeOnly.Minute, timeOnly.Second, timeOnly.Millisecond, timeSpan);
                        }
                        return value;
                    }
                    if (type == typeof(TimeSpan))
                    {
                        if (value is DateOnly)
                        {
                            throw new Exception("无法从 DateOnly 转到TimeSpan!");
                        }
                        else if (value is TimeOnly timeOnly)
                        {
                            value = new TimeSpan(0, timeOnly.Hour, timeOnly.Minute, timeOnly.Second, timeOnly.Millisecond);
                        }
                        return value;
                    }
                }
#endif
#endregion

                #region DateTimeOffset 转 DateTime
                if (value?.GetType() == typeof(DateTimeOffset) && type == typeof(DateTime))
                {
                    return ((DateTimeOffset)value).DateTime;
                }
                #endregion
                #region DateTime 转 DateTimeOffset
                if (value?.GetType() == typeof(DateTime) && type == typeof(DateTimeOffset))
                {
                    return new DateTimeOffset((DateTime)value);
                }
                #endregion
                #region TimeSpan 转 DateTime DateTimeOffset
                if (value is TimeSpan time && (type == typeof(DateTimeOffset) || type == typeof(DateTime)))
                {
                    if (type == typeof(DateTime))
                    {
                        value = new DateTime(1970, 01, 01, time.Hours, time.Minutes, time.Seconds, time.Milliseconds);
                    }
                    else if (type == typeof(DateTimeOffset))
                    {
                        value = new DateTimeOffset(1970, 01, 01, time.Hours, time.Minutes, time.Seconds, time.Milliseconds, timeSpan);
                    }
                    return value;
                }
                #endregion
                #region 字符串转bool
                if (type == typeof(bool) && value is string)
                {
                    var tmp = value.ToString().ToUpper();
                    if (new string[] { "OK", "YES", "TRUE", "1", "是" }.Contains(tmp)) return true;
                    else return false;
                }
                #endregion
                #region 字符串转guid
                if (type == typeof(Guid) && value is string str)
                {
                    return Guid.Parse(str);
                }
                #endregion
                #region 可以使用Convert.ToXXX的转换
                var typeCode = type.GetTypeCode();
                if (_baseTypes.Contains(typeCode))
                {
                    return _baseConvert(typeCode, value);
                }
                #endregion
                #region 其他 使用 JsonConvert 实现
                return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value), type);
                #endregion
            }
            else
            {
                //兼容从json字符串反序列化
                if (value is string && type.IsClass) return JsonConvert.DeserializeObject(value.ToString(), type);
                //引用类型
                return value;
            }
        }

        /// <summary>
        /// 通用转换方法
        /// </summary>
        public static T ToWithDefault<T>(this object value, T defaultValue, params object[] parameters)
        {
            if (value is T) return (T)value;
            Type type = typeof(T);
            if (value == null || value is DBNull)
            {
                //引用类型: 返回默认 即: null
                if (!type.IsValueType) return default;
                //可空类型: 返回默认 即: null
                if (type.IsNullable()) return default;
            }
            return (T)value.ToWithDefault(type, defaultValue, parameters);
        }

        /// <summary>
        /// 通用转换方法
        /// </summary>
        public static object ToWithDefault(this object value, Type type, object defaultValue, params object[] parameters)
        {
            if (type == null) return defaultValue;
            if (value == null || value is DBNull)
            {
                //引用类型: 返回默认 即: null
                if (!type.IsValueType) return null;
                //可空类型: 返回默认 即: null
                if (type.IsNullable()) return null;
            }

            try
            {
                return value.To(type, parameters);
            }
            catch
            {
                Console.WriteLine($"ToWithDefault触发异常[{value} => {type.FullName}],注意频繁异常会降低程序性能.");
                return defaultValue;
            }
        }
#endregion

        #region 基于同名属性的对象映射 object.Mapper<TResult>()
        #region 对外扩展接口
        /// <summary>
        /// 对象映射，基于同名属性转换原则<para></para>
        /// 调用方法:
        /// <para></para>
        /// var person=new Person();<para></para>
        /// var dto=person.Mapper&lt;PersonDto>();<para></para>
        /// var persons=new List&lt;Person>();<para></para>
        /// var dtos=persons.Mapper&lt;List&lt;PersonDto>>();<para></para>
        /// </summary>
        /// <typeparam name="TResult">目标类型</typeparam>
        /// <param name="src">原实例</param>
        /// <param name="containsRepeatReference">是否考虑引用关系</param>
        /// <param name="null2Default">是否将null值转换为默认值,而不是抛出异常</param>
        /// <returns></returns>
        public static TResult Mapper<TResult>(this object src, bool containsRepeatReference = true, bool null2Default = true)
        {
            var destType = typeof(TResult);
            if (src.IsNullOrDBNull())
            {
                if (null2Default || !destType.IsValueType || destType.IsNullable()) return default;
                throw new Exception($"无法从 null or dbnull 转换为 {destType.GetClassFullName()}");
            }
            var srcType = src.GetType();

            if (srcType == destType) return (TResult)src;
            return (TResult)MapperHelper.Mapper(srcType, destType, src, containsRepeatReference, null2Default);
        }

        /// <summary>
        /// 对象映射，基于同名属性转换原则<para></para>
        /// 调用方法:
        /// <para></para>
        /// var person=new Person();<para></para>
        /// var dto=person.Mapper&lt;Person,PersonDto>();<para></para>
        /// var persons=new List&lt;Person>();<para></para>
        /// var dtos=persons.Mapper&lt;List&lt;Person>,List&lt;PersonDto>>();<para></para>
        /// </summary>
        /// <typeparam name="TFrom">源类型</typeparam>
        /// <typeparam name="TDest">目标类型</typeparam>
        /// <param name="src"></param>
        /// <param name="containsRepeatReference">是否考虑引用关系</param>
        /// <param name="null2Default">是否将null值转换为默认值,而不是抛出异常</param>
        /// <remarks>
        /// 注意：相对于 <c>person.Mapper&lt;PersonDto>()</c> 增加指定源目标类型
        /// </remarks>
        /// <returns></returns>
        public static TDest Mapper<TFrom, TDest>(this object src, bool containsRepeatReference = true, bool null2Default = true)
        {
            var destType = typeof(TDest);
            if (src.IsNullOrDBNull())
            {
                if (null2Default || !destType.IsValueType || destType.IsNullable()) return default;
                throw new Exception($"无法从 null or dbnull 转换为 {destType.GetClassFullName()}");
            }
            var srcType = typeof(TFrom);
            if (srcType == destType) return (TDest)src;
            return (TDest)MapperHelper.Mapper(srcType, destType, src, containsRepeatReference, null2Default);
        }

        /// <summary>
        /// 对象映射，基于同名属性转换原则<para></para>
        /// 调用方法:
        /// <para></para>
        /// var person=new Person();<para></para>
        /// var dto=person.Mapper(typeof(PersonDto));<para></para>
        /// var persons=new List&lt;Person>();<para></para>
        /// var dtos=persons.Mapper(typeof(List&lt;PersonDto>));<para></para>
        /// </summary>
        /// <param name="src"></param>
        /// <param name="type">目标类型</param>
        /// <param name="containsRepeatReference">是否考虑引用关系</param>
        /// <param name="null2Default">是否将null值转换为默认值,而不是抛出异常</param>
        /// <returns></returns>
        public static object Mapper(this object src, Type type, bool containsRepeatReference = true, bool null2Default = true)
        {
            if (type is null) throw new ArgumentNullException(nameof(type));
            if (src.IsNullOrDBNull())
            {
                if (null2Default || !type.IsValueType || type.IsNullable()) return type.GetDefault();
                throw new Exception($"无法从 null or dbnull 转换为 {type.GetClassFullName()}");
            }

            var srcType = src.GetType();
            var destType = type;
            return MapperHelper.Mapper(srcType, destType, src, containsRepeatReference, null2Default);
        }

        ///<summary>
        /// 对象映射，基于同名属性转换原则<para></para>
        /// 调用方法:
        /// <para></para>
        /// var person=new Person();<para></para>
        /// var dto=person.Mapper(typeof(Person),typeof(PersonDto));<para></para>
        /// var persons=new List&lt;Person>();<para></para>
        /// var dtos=persons.Mapper(typeof(List&lt;Person>),typeof(List&lt;PersonDto>));<para></para>
        /// </summary>
        /// <param name="src"></param>
        /// <param name="fromType">源类型</param>
        /// <param name="destType">目标类型</param>
        /// <param name="containsRepeatReference">是否考虑引用关系</param>
        /// <param name="null2Default">是否将null值转换为默认值,而不是抛出异常</param>
        /// <remarks>
        /// 注意：相对于 <c>person.Mapper(typeof(PersonDto))</c> 增加指定源目标类型
        /// </remarks>
        /// <returns></returns>
        public static object Mapper(this object src, Type fromType, Type destType, bool containsRepeatReference = true, bool null2Default = true)
        {
            if (fromType is null) throw new ArgumentNullException(nameof(fromType));
            if (destType is null) throw new ArgumentNullException(nameof(destType));
            if (src.IsNullOrDBNull())
            {
                if (null2Default || !destType.IsValueType || destType.IsNullable()) return destType.GetDefault();
                throw new Exception($"无法从 null or dbnull 转换为 {destType.GetClassFullName()}");
            }
            return MapperHelper.Mapper(fromType, destType, src, containsRepeatReference, null2Default);
        }
        #endregion

        #region 废弃 基于反射实现 Mapper
        //private static object mapper(object src, Type srcType, Type destType)
        //{
        //    //src、srcType、destType 不可能为空
        //    Ensure.NotNull(src, nameof(src));
        //    Ensure.NotNull(srcType, nameof(srcType));
        //    Ensure.NotNull(destType, nameof(destType));

        //    //优先使用Roslyn
        //    var res = RoslynMapper.TryMapper(src, srcType, destType);
        //    if (res.Success)
        //    {
        //        //logger.LogInformation($"roslyn");
        //        return res.Data;
        //    }

        //    //logger.LogInformation($"反射");
        //    //失败时使用反射
        //    //缓存转换过程，防止循环引用
        //    var container = new Dictionary<(object src, Type srcType, Type destType), object>();
        //    return mapper(src, srcType, destType, container);
        //}

        //private static object mapper(object src, Type srcType, Type destType, Dictionary<(object src, Type srcType, Type destType), object> container)
        //{
        //    //null值的转换
        //    if (src == null || src is DBNull)
        //    {
        //        return destType.GetDefault();
        //    }

        //    if (destType == srcType)
        //    {
        //        return src;
        //    }

        //    //简单类型使用 To 方法转换 (这个方法应该不会出现 简单类型之间的转换)
        //    if ((srcType.IsValueType || src is string) && (destType.IsValueType || destType == typeof(string)))
        //    {
        //        var key = (src, srcType, destType);
        //        if (container.ContainsKey(key))
        //        {
        //            return container[key];
        //        }
        //        var destValue = src.To(destType);
        //        container.Add(key, destValue);
        //        return destValue;
        //    }

        //    #region 集合数组间转换
        //    if (srcType.IsConvertCollectionsOrArrary() && destType.IsConvertCollectionsOrArrary())
        //    {
        //        //先创建集合,最后根据需要转换成 Array
        //        Type desFType = destType.IsArray ? destType.GetElementType() : destType.GenericTypeArguments[0];
        //        Type srcFType = srcType.IsArray ? srcType.GetElementType() : srcType.GenericTypeArguments[0];
        //        var tmpDestType = typeof(List<>).MakeGenericType(desFType);
        //        var destList = Activator.CreateInstance(tmpDestType);

        //        object tmpList = src;
        //        Type tmpType = srcType;

        //        tmpType = typeof(List<>).MakeGenericType(srcFType);
        //        tmpList = Activator.CreateInstance(tmpType);
        //        //循环转换
        //        foreach (var src2 in src as IEnumerable)
        //        {
        //            tmpType.GetMethod("Add").Invoke(tmpList, new object[] { src2 });
        //        }

        //        //开始集合间拷贝数据
        //        var count = (int)tmpType.GetProperty("Count").GetValue(tmpList);
        //        var indexProp = tmpType.GetProperty("Item");
        //        for (var i = 0; i < count; i++)
        //        {
        //            var src2 = indexProp.GetValue(tmpList, new object[] { i });
        //            //引用类型,递归转
        //            object newValue = null;
        //            var key = (src2, srcFType, desFType);
        //            if (container.ContainsKey(key))
        //            {
        //                newValue = container[key];
        //            }
        //            else
        //            {
        //                newValue = mapper(src2, srcFType, desFType, container);
        //            }
        //            tmpDestType.GetMethod("Add").Invoke(destList, new object[] { newValue });
        //        }

        //        //转移为最终的数组或集合
        //        if (destType.IsArray)
        //        {
        //            return tmpDestType.GetMethod("ToArray").Invoke(destList, new object[0]);
        //        }
        //        return destList;
        //    }
        //    #endregion

        //    #region 非集合转换
        //    object dest = Activator.CreateInstance(destType);
        //    container.Add((src, srcType, destType), dest);
        //    var props = src.GetType().GetProperties();
        //    var props2 = destType.GetProperties();
        //    for (var i = 0; i < props.Count(); i++)
        //    {
        //        var prop = props[i];
        //        var destProp = props2.FirstOrDefault(p => p.Name == prop.Name);
        //        if (destProp != null)
        //        {
        //            //过滤没有set方法的属性
        //            if (destProp.GetSetMethod() == null) continue;
        //            var val = prop.GetValue(src);
        //            var destPropType = destProp.PropertyType;
        //            var srcPropType = prop.PropertyType;
        //            if (destPropType == srcPropType)
        //            {
        //                //可以直接转
        //                destProp.SetValue(dest, val);
        //                continue;
        //            }

        //            if (val == null || val is DBNull)
        //            {
        //                destProp.SetValue(dest, destProp.PropertyType.GetDefault());
        //                continue;
        //            }

        //            #region 其他类型转string
        //            if (destProp.PropertyType == typeof(string))
        //            {
        //                if (prop.PropertyType == typeof(DateTime) || prop.PropertyType == typeof(DateTime?)
        //                    || prop.PropertyType == typeof(DateTimeOffset) || prop.PropertyType == typeof(DateTimeOffset?)
        //                    || prop.PropertyType == typeof(Guid) || prop.PropertyType == typeof(Guid?))
        //                {
        //                    //日期或guid转字符串
        //                    var formatter = "";
        //                    var converter = prop.GetCustomAttributes().FirstOrDefault(i => i.GetType() == typeof(MapperArgumentsAttribute)) as MapperArgumentsAttribute;
        //                    if (converter == null)
        //                    {
        //                        converter = destProp.GetCustomAttributes().FirstOrDefault(i => i.GetType() == typeof(MapperArgumentsAttribute)) as MapperArgumentsAttribute;
        //                    }
        //                    if (converter != null && converter.Args?.Length > 0)
        //                    {
        //                        formatter = converter.Args.FirstOrDefault().ToString();
        //                    }
        //                    destProp.SetValue(dest, val.To(destProp.PropertyType, formatter));
        //                    continue;
        //                }
        //                destProp.SetValue(dest, val?.ToString());
        //                continue;
        //            }
        //            #endregion

        //            #region 字符串转日期或guid
        //            if (prop.PropertyType == typeof(string))
        //            {
        //                if (destProp.PropertyType == typeof(DateTime) || destProp.PropertyType == typeof(DateTime?)
        //                            || destProp.PropertyType == typeof(DateTimeOffset) || destProp.PropertyType == typeof(DateTimeOffset?)
        //                            || destProp.PropertyType == typeof(Guid) || destProp.PropertyType == typeof(Guid?))
        //                {
        //                    //字符串转日期
        //                    var formatter = "";
        //                    var converter = prop.GetCustomAttributes().FirstOrDefault(i => i.GetType() == typeof(MapperArgumentsAttribute)) as MapperArgumentsAttribute;
        //                    if (converter == null)
        //                    {
        //                        converter = destProp.GetCustomAttributes().FirstOrDefault(i => i.GetType() == typeof(MapperArgumentsAttribute)) as MapperArgumentsAttribute;
        //                    }
        //                    if (converter != null && converter.Args?.Length > 0)
        //                    {
        //                        formatter = converter.Args.FirstOrDefault().ToString();
        //                    }
        //                    destProp.SetValue(dest, val.To(destProp.PropertyType, formatter));
        //                    continue;
        //                }
        //            }
        //            #endregion

        //            if (destProp.PropertyType.IsValueType)
        //            {
        //                destProp.SetValue(dest, val.To(destProp.PropertyType));
        //                continue;
        //            }

        //            //集合
        //            if (srcPropType.IsConvertCollectionsOrArrary() && destPropType.IsConvertCollectionsOrArrary())
        //            {
        //                if (destPropType.IsAssignableFrom(srcPropType))
        //                {
        //                    destProp.SetValue(dest, val);
        //                    continue;
        //                }
        //            }

        //            //引用类型,递归转
        //            object newValue = null;
        //            var key = (val, prop.PropertyType, destProp.PropertyType);
        //            if (container.ContainsKey(key))
        //            {
        //                newValue = container[key];
        //            }
        //            else
        //            {
        //                newValue = mapper(val, prop.PropertyType, destProp.PropertyType, container);
        //            }
        //            destProp.SetValue(dest, newValue);
        //        }
        //    }
        //    #endregion
        //    return dest;
        //} 
        #endregion
        #endregion

        #region Modify 递归修改指定名称的属性值 object.Modify<T>(propName,obj=>obj)
        /// <summary>
        /// 根据属性名递归修改属性值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="model"></param>
        /// <param name="propName">属性名</param>
        /// <param name="modifyAction">根据旧值,修改后返回新值</param>
        /// <returns></returns>
        public static T Modify<T>(this T model, string propName, Func<object, object> modifyAction)
        {
            if (model == null) return model;
            _filterDeal(model);
            return model;

            void _filterDeal(object model)
            {
                if (model == null) return;
                var type = model.GetType();
                //这里不接受简单类型
                if (type.IsSimpleType()) return;
                //集合
                if (CollectNames.Any(p => type.FullName.StartsWith(p)))
                {
                    var count = (int)type.GetProperties().FirstOrDefault(prop => prop.Name == "Count").GetValue(model);
                    if (count == 0)
                    {
                        //元素个数为0
                        return;
                    }
                    else
                    {
                        //循环转换
                        var indexProp = type.GetProperty("Item");
                        for (var i = 0; i < count; i++)
                        {
                            var src2 = indexProp.GetValue(model, new object[] { i });
                            _filterDeal(src2);
                        }
                    }
                }
                else if (type.IsArray)
                {
                    //数组
                    var count = (int)type.GetProperties().FirstOrDefault(prop => prop.Name == "Length").GetValue(model);
                    if (count == 0)
                    {
                        //元素个数为0
                        return;
                    }
                    else
                    {
                        //是集合,且有数据
                        var indexProp = type.GetProperty("Item");
                        foreach (var src2 in model as Array)
                        {
                            _filterDeal(src2);
                        }
                    }
                }
                else
                {
                    //dto对象
                    var props = model.GetType().GetProperties();
                    foreach (var prop in props)
                    {
                        if (prop.Name == propName && prop.CanWrite)
                        {
                            var old = prop.GetValue(model);
                            try
                            {
                                var newValue = modifyAction(old);
                                prop.SetValue(model, newValue);
                            }
                            catch { }
                        }
                        else
                        {
                            _filterDeal(prop.GetValue(model));
                        }
                    }
                }
            }
        }
        #endregion

        #region 使用dto对象改变实体对象上的值 object.ModifyByDto(dto)
        /// <summary>
        /// 将指定dto对象的属性值投影到当前对象（entity）上，改变entity的属性值，基于同名属性反射<para></para>
        /// 注意：这个方法是为根据dto更新entity提供的，调用此方法时，无论是entity还是dto都不应该是集合，执行主体逻辑如下：
        /// <list type="bullet">
        /// <item>如果dto为null，直接返回entity；</item>
        /// <item>如果dto的类型和entity的类型相同，则直接返回dto对象；</item>
        /// <item>如果entity为null，则新创建一个entity实例，修改后返回新创建的实例；</item>
        /// <item>属性先进行比较，相等则不改变；</item>
        /// <item>对于集合类型，直接覆盖；</item>
        /// <item>对于引用类型，递归修改；</item>
        /// </list>
        /// </summary>
        /// <typeparam name="TResult">目标类型</typeparam>
        /// <param name="dto">dto对象，将这个对象的属性映射到当前对象上，改变当前对象的属性值</param>
        /// <param name="baseObj">基础对象,不能为null</param>
        public static TResult ModifyByDto<TResult>(this TResult baseObj, object dto) where TResult : class
        {
            if (dto == null) return baseObj;
            if (baseObj == null) throw new ArgumentNullException(nameof(baseObj), "投影到的对象entity不允许为null");
            return mapperModify(dto, baseObj);
        }

        private static TResult mapperModify<TResult>(object src, TResult baseObj) where TResult : class
        {
            //缓存转换过程，防止循环引用
            var container = new Dictionary<(object src, Type destType), object>();
            TResult dest = baseObj;
            if (dest == null)
            {
                dest = (TResult)Activator.CreateInstance(typeof(TResult));
            }
            container.Add((src, typeof(TResult)), dest);
            return (TResult)mapperModify(src, dest, typeof(TResult), container);
        }

        private static object mapperModify(object src, object dest, Type destType, Dictionary<(object src, Type destType), object> container)
        {
            //null值的转换
            if (src == null || src is DBNull)
            {
                return destType.GetDefault();
            }
            var srcType = src.GetType();
            if (srcType == destType)
            {
                return src;
            }
            #region 集合转换
            //集合转换
            if (CollectNames.Any(p => srcType.FullName.StartsWith(p)) && CollectNames.Any(p => destType.FullName.StartsWith(p)))
            {
                var geneType = destType.GenericTypeArguments[0];
                destType = typeof(List<>).MakeGenericType(geneType);
                if ((int)src.GetType().GetProperties().FirstOrDefault(prop => prop.Name == "Count").GetValue(src) == 0)
                {
                    //是集合,但元素个数为0
                    var list = Activator.CreateInstance(destType);
                    return list;
                }
                else
                {
                    //是集合,且有数据
                    var list = Activator.CreateInstance(destType);
                    //循环转换
                    var count = (int)src.GetType().GetProperty("Count").GetValue(src);
                    var indexProp = src.GetType().GetProperty("Item");
                    for (var i = 0; i < count; i++)
                    {
                        var src2 = indexProp.GetValue(src, new object[] { i });
                        //引用类型,递归转
                        object newValue = null;
                        var key = (src2, geneType);
                        if (container.ContainsKey(key))
                        {
                            newValue = container[key];
                        }
                        else
                        {
                            object ele = null;
                            var cons = geneType.GetConstructors().FirstOrDefault(con => con.GetParameters().Length == 0);
                            if (cons != null)
                            {
                                ele = cons.Invoke(new object[0]);
                            }
                            container.Add((src2, geneType), ele);
                            newValue = mapperModify(src2, ele, geneType, container);
                        }
                        destType.GetMethod("Add").Invoke(list, new object[] { newValue });
                    }
                    return list;
                }
            }
            //数组转换 和集合转换逻辑一致,代码稍有不同
            if (destType.IsArray && srcType.IsArray)
            {
                var geneType = destType.GetElementType();
                destType = typeof(List<>).MakeGenericType(geneType);
                if ((int)src.GetType().GetProperties().FirstOrDefault(prop => prop.Name == "Length").GetValue(src) == 0)
                {
                    //是数组,但元素个数为0
                    var list = Activator.CreateInstance(destType);
                    return destType.GetMethod("ToArray").Invoke(list, new object[0]);
                }
                else
                {
                    //是集合,且有数据
                    var list = Activator.CreateInstance(destType);
                    //循环转换
                    var indexProp = src.GetType().GetProperty("Item");
                    foreach (var src2 in src as Array)
                    {
                        object newValue = null;
                        var key = (src2, geneType);
                        if (container.ContainsKey(key))
                        {
                            newValue = container[key];
                        }
                        else
                        {
                            object ele = null;
                            var cons = geneType.GetConstructors().FirstOrDefault(con => con.GetParameters().Length == 0);
                            if (cons != null)
                            {
                                ele = cons.Invoke(new object[0]);
                            }
                            container.Add((src2, geneType), ele);
                            newValue = mapperModify(src2, ele, geneType, container);
                        }
                        destType.GetMethod("Add").Invoke(list, new object[] { newValue });
                    }
                    return destType.GetMethod("ToArray").Invoke(list, new object[0]);
                }
            }
            #endregion
            #region 非集合转换
            var props = src.GetType().GetProperties();
            var props2 = destType.GetProperties();
            foreach (var prop in props)
            {
                var destProp = props2.FirstOrDefault(p => p.Name == prop.Name);
                if (destProp != null)
                {
                    //过滤没有set方法的属性
                    if (destProp.GetSetMethod() == null) continue;
                    var val = prop.GetValue(src);
                    var destVal = destProp.GetValue(dest);
                    //相等,无需改变值
                    if (prop.PropertyType == destProp.PropertyType)
                    {
                        try
                        {
                            if (val == null && destProp == null) continue;
                            if (val != null && val.Equals(destVal)) continue;
                        }
                        catch { }
                    }

                    if (val == null)
                    {
                        destProp.SetValue(dest, null);
                        continue;
                    }
                    if (prop.PropertyType.IsValueType || prop.PropertyType == destProp.PropertyType)
                    {
                        //值类型或类型相同直接转
                        destProp.SetValue(dest, val);
                        continue;
                    }
                    //引用类型,递归转
                    object newValue = null;
                    var key = (val, destProp.PropertyType);
                    if (container.ContainsKey(key))
                    {
                        newValue = container[key];
                    }
                    else
                    {
                        object ele = destVal;
                        if (ele == null)
                        {
                            var cons = destProp.PropertyType.GetConstructors().FirstOrDefault(con => con.GetParameters().Length == 0);
                            if (cons != null)
                            {
                                ele = cons.Invoke(new object[0]);
                            }
                        }
                        container.Add((val, destProp.PropertyType), ele);
                        newValue = mapperModify(val, ele, destProp.PropertyType, container);
                    }
                    //相等的直接跳过
                    if (newValue == val) continue;
                    destProp.SetValue(dest, newValue);
                }
            }
            #endregion
            return dest;
        }
        #endregion

        #region DeepClone object.DeepClone()
        /// <summary>
        /// 深度克隆对象实例，支持 <c>简单类poco</c>、<c>数组</c>、<c>List</c>、<c>dicitionary</c>、<c>ValueTuple&lt;></c>、<c>匿名类型</c> 等, 示例代码:
        /// <code>
        /// var list=new List&lt;Person>()
        /// {
        ///     new Person{ Id = 1, Name = "小明" },
        ///     new Person{ Id = 2, Name = "小刚" }
        /// }
        /// var newList = list.DeepClone(false);//因为数据格式简单,没有冗余、循环的引用,传入 false 将克隆缓存关掉以提升性能
        /// </code>
        /// 当实例内部有冗余、循环的引用时:
        /// <code>
        /// var root = new Node { Id = 1, Children = new List&lt;Node>() };
        /// var current = new Node { Id = 2,Parent=root };
        /// root.Children.Add(current);
        /// var newRoot = root.DeepClone(true);//因为数据之间有冗余、循环的引用, 传入 true 打开克隆缓存，引用关系将被一起克隆
        /// </code>
        /// </summary>
        /// <remarks>
        /// 注意：本方法优先使用 <see cref="ICloneable"/> 中的 <c>Clone</c> 方法
        /// </remarks>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="containsRepeatReference">是否考虑重复的引用,当要克隆的对象内部没有冗余的、循环的引用时,将此设为 <c>false</c> 可能提升一半性能</param>
        /// <param name="capacity">当 <c>containsRepeatReference</c> 设为true时,缓存字典的默认容量</param>
        /// <returns></returns>
        public static T DeepClone<T>(this T obj, bool containsRepeatReference = true, int capacity = 32)
            => DeepCloneHelper.DeepColne(obj, containsRepeatReference, capacity);
        #endregion

        private static List<string> CollectNames = new List<string>()
        {
            "System.Collections.Generic.List`1",
            "System.Collections.Generic.IList`1",
            "System.Collections.Generic.IEnumerable`1",
            "System.Collections.Generic.ICollection`1"
        };

        #region ToJson & ToJsonFast
        /// <summary>
        /// 序列化为json字符串
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="settings">序列化设置对象</param>
        /// <returns></returns>
        public static string ToJson(this object obj, JsonSerializerSettings settings = null)
        {
            if (obj == null) return null;
            return JsonConvert.SerializeObject(obj, settings);
        }

        /// <summary>
        /// 指定常用的设置,序列化为json字符串
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="dateFormatString">日期时间格式</param>
        /// <param name="isLongToString">是否将long型转为字符串</param>
        /// <param name="IgnoreNull">是否忽略null值的属性</param>
        /// <param name="enum2String">是否将枚举转换为字符串</param>
        /// <param name="lowerCamelCase">属性名称的首字母是否小写</param>
        /// <param name="isIntend">是否格式缩进</param>
        /// <param name="isAllToString">是否将所有数据类型转换为字符串</param>
        /// <param name="allNumDigit">设定的所有数字的最大小数位数(默认为null，即: 不限制)</param>
        /// <param name="decimalDigit">仅针对decimal设定的最大小数位数(默认为null，即: 不限制)</param>
        /// <param name="otherSettings">其他的设置</param>
        /// <returns></returns>
        public static string ToJsonFast(this object obj, string dateFormatString = "yyyy-MM-dd HH:mm:ss", bool IgnoreNull = false, bool enum2String = true, bool lowerCamelCase = false, bool isIntend = false, bool isLongToString = false, bool isAllToString = false, int? allNumDigit = null, int? decimalDigit = null, Action<JsonSerializerSettings> otherSettings = null)
        {
            var settings = new JsonSerializerSettings()
            {
                DateFormatString = dateFormatString,
                Converters = new List<JsonConverter>()
            };
            if (IgnoreNull)
            {
                settings.NullValueHandling = NullValueHandling.Ignore;
            }
            if (enum2String)
            {
                settings.Converters.Add(new StringEnumConverter());
            }
            if (lowerCamelCase)
            {
                settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            }
            if (isIntend)
            {
                settings.Formatting = Formatting.Indented;
            }
            settings.Converters.Add(new PrimitiveConvertor(isLongToString, isAllToString, allNumDigit, decimalDigit));
            otherSettings?.Invoke(settings);
            return JsonConvert.SerializeObject(obj, settings);
        }
        #endregion

        /// <summary>
        /// 是否是数字类型
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool IsNumeric(this object obj)
        {
            if (obj == null) return false;
            return obj.GetType().IsNumeric();
        }

        /// <summary>
        /// 是否是枚举类型
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool IsEnum(this object obj)
        {
            if (obj == null) return false;
            return obj.GetType().IsEnum;
        }

        /// <summary>
        /// obj is null || obj is DBNull
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool IsNullOrDBNull(this object obj) => obj is null || obj is DBNull;
    }

    /// <summary>
    /// 类转换时的参数
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class MapperArgumentsAttribute : Attribute
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="args"></param>
        public MapperArgumentsAttribute(params object[] args)
        {
            Args = args;
        }

        /// <summary>
        /// 参数数组
        /// </summary>
        public object[] Args { get; }
    }
}
